#include "message.h"

#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

#include "log.h"

typedef message _message;

static char *connection_type_name(connection connection);

message *message_from_json(message *message, const cJSON *json) {
	if (!json) {
		log_warn("json为空");
		goto json_is_null;
	}
	cJSON *object[6] = {NULL};
	if ( // 找不到指定元素，返回NULL
		!(object[0] = cJSON_GetObjectItem(json, "connection")) ||  //
		!(object[1] = cJSON_GetObjectItem(json, "device_name")) || //
		!(object[2] = cJSON_GetObjectItem(json, "topic")) ||	   //
		!(object[3] = cJSON_GetObjectItem(json, "timestamp")) ||   //
		!(object[4] = cJSON_GetObjectItem(json, "size")) ||		   //
		!(object[5] = cJSON_GetObjectItem(json, "content"))		   //
	) {
		log_warn("json解析错误");
		goto json_parse_fail;
	}
	size_t device_name_length = strlen(object[1]->valuestring);
	size_t topic_length = strlen(object[2]->valuestring);
	uint32_t content_length = object[4]->valueint;
	if (!message) {
		message = (_message *)calloc(1, sizeof(_message));
		if (!message) {
			log_warn("分配消息空间失败");
			goto alloc_message_fail;
		}
		message->device_name =
			(char *)calloc(device_name_length + 1, sizeof(char));
		if (!message->device_name) {
			log_warn("分配设备名称空间失败");
			goto alloc_device_name_fail;
		}
		message->topic = (char *)calloc(topic_length + 1, sizeof(char));
		if (!message->topic) {
			log_warn("分配话题空间失败");
			goto alloc_topic_fail;
		}
		message->content = (char *)calloc(content_length + 1, sizeof(char));
		if (!message->content) {
			log_warn("分配消息内容空间失败");
			goto alloc_content_fail;
		}
	}
	message->message_type = server_to_device;
	message->connection = object[0]->valueint;
	memcpy(message->device_name, object[1]->valuestring, device_name_length);
	memcpy(message->topic, object[2]->valuestring, topic_length);
	message->timestamp = object[3]->valueint;
	message->size = object[4]->valueint;
	// memcpy(message->content, object[4]->valuestring, content_length);
	char *s = object[5]->valuestring;
	unsigned char *d = message->content;
	for (uint32_t i = 0; i < content_length; ++i) {
		sscanf(s + i * 2, "%2hhx ", d + i);
	}
	return message;

alloc_content_fail:
	free(message->topic);
alloc_topic_fail:
	free(message->device_name);
alloc_device_name_fail:
	free(message);
alloc_message_fail:
json_parse_fail:
json_is_null:
	return NULL;
}
/**
	@brief 将message转换为json
	@param const_message* message 要转换的消息
	@param cJSON* json 存储的json，非空，向其赋值；为空，在函数中创建
	@return 返回创建的json
*/
cJSON *message_to_json(cJSON *json, const message *message) {
	if (!message) {
		log_warn("消息为空");
		goto message_is_null;
	}
	cJSON *_json = json;
	if (!_json) {
		_json = cJSON_CreateObject();
		if (!_json) {
			log_warn("创建json失败");
			goto alloc_json_fail;
		}
	}
	uint32_t content_length = message->size;
	unsigned char *s = (unsigned char *)message->content;
	if (!s) {
		log_warn("消息内容为空");
	}
	char *d = (char *)calloc(content_length * 3 + 1, sizeof(char));
	if (!d) {
		log_warn("分配内容空间失败");
		goto alloc_content_fail;
	}
	for (uint32_t i = 0; i < content_length; ++i) {
		sprintf(d + i * 2, "%02hhx ", s[i]);
	}
	if ( // 添加失败，返回NULL
		!cJSON_AddNumberToObject(_json, "connection", message->connection) || //
		!cJSON_AddStringToObject(_json, "device_name",
								 message->device_name) ||		   //
		!cJSON_AddStringToObject(json, "topic", message->topic) || //
		!cJSON_AddNumberToObject(_json, "timestamp",
								 message->timestamp) ||			  //
		!cJSON_AddNumberToObject(_json, "size", message->size) || //
		!cJSON_AddStringToObject(_json, "content", d)			  //
	) {
		log_warn("向json添加失败");
		goto add_to_json_fail;
	}
	return _json;

add_to_json_fail:
	free(d);
alloc_content_fail:
	if (!json) {
		free(_json);
	}
alloc_json_fail:
message_is_null:
	return NULL;
}
/**
	@brief 销毁message，仅用于在函数中创建的
	@param message *message 要销毁的message
	@return 销毁成功，返回NULL；失败，返回传入指针
*/
message *message_destory(message *message) {
	if (!message) {
		return NULL;
	}
	if (message->device_name) {
		free(message->device_name);
		message->device_name = NULL;
	}
	if (message->topic) {
		free(message->topic);
		message->topic = NULL;
	}
	if (message->content) {
		free(message->content);
		message->content = NULL;
	}
	free(message);
	return NULL;
}
/**
	@brief 显示消息
	@param const_message* message 要显示的消息
	@return 无
*/
void message_display(const message *message) {

	log_info("消息地址：%p", message);
	if (!message) {
		return;
	}
	log_info("连接类型：%s", connection_type_name(message->connection));
	log_info("设备名称：%s", message->device_name);
	log_info("主题：%s", message->topic);
	log_info("时间戳：%u", message->timestamp);
	log_info("内容大小：%u", message->size);
	uint32_t i = 0;
	uint32_t size = message->size;
	const char *p = (char *)message->content;
	for (i = 0; i < size; ++i) {
		if (!isprint(p[i])) {
			break;
		}
	}
	log_info("内容：");
	if ((i == size) && (p[i] == '\0')) {
		log_info("%s", message->content);
	} else {
		for (i = 0; i < size; ++i) {
			printf("%03x ", p[i]);
		}
		printf("\n");
	}
}
static char *connection_type_name(connection connection) {
	switch (connection) {
		case connection_none:
			return "无";
		case connection_bluetooth:
			return "蓝牙";
		case connection_lora:
			return "LoRa";
		case connection_mqtt:
			return "MQTT";
		default:
			return "未知";
	}
}